#include "StdAfx.h"
#include "FD3D9DynamicRHI.h"

#include "vertexbuffer.h"
#include "mathlib.h"
#include "plane.h"
#include "vector4.h"
#include "ColorValue.h"

// Globals

/**
*	Used for checking if the device is lost or not.
*	Using the global variable is not enough, since it's updated to rarely.
*/

using namespace RenderSystem;
using namespace Common;

extern bool g_bSupportsHardwareInstancing = true;
extern float g_fDepthBiasOffset;

// Vertex state.
void FD3D9DynamicRHI::SetStreamSource(UINT uStreamIndex, VertexBuffer* pVertexBuffer, UINT uStride, bool bUseInstanceIndex, UINT uNumVerticesPerInstance, UINT uNumInstances)
{
	//convert the vertex buffer into d3d vertex buffer

	assert(uStreamIndex < m_uNumVertexStreams);

	bool bUseStride = true;
	DWORD Frequency = 1;
	// Set the vertex stream frequency.
	if(g_bSupportsHardwareInstancing)
	{
		m_uPendingNumInstances = 1;
		if (bUseInstanceIndex || uNumInstances > 1)
		{
			Frequency = bUseInstanceIndex ? 
				(D3DSTREAMSOURCE_INSTANCEDATA | 1) :
			(D3DSTREAMSOURCE_INDEXEDDATA | uNumInstances);
		}
	}
	else
	{
		m_uPendingNumInstances = uNumInstances;
		// some instanced calls may have only one instance (ProcBuildings)
		if (/*NumInstances > 1 && */ bUseInstanceIndex)
		{
			m_PendingStreams[uStreamIndex].pVertexBuffer = pVertexBuffer;
			m_PendingStreams[uStreamIndex].uStride = uStride;
			m_PendingStreams[uStreamIndex].uNumVerticesPerInstance = uNumVerticesPerInstance;
			bUseStride = FALSE; // We don't want this to advance per instance, but rather be advanced manually for fake instancing
			m_uUpdateStreamForInstancingMask |= 1<<uStreamIndex;
		}
	}
	m_pDirect3DDevice->SetStreamSource(uStreamIndex, pVertexBuffer, 0, bUseStride ? uStride : 0);
	m_pDirect3DDevice->SetStreamSourceFreq(uStreamIndex, Frequency);
}

// Rasterizer state.
void FD3D9DynamicRHI::SetRasterizerState(const RasterizerState& rNewState)
{
	m_pDirect3DDevice->SetRenderState(D3DRS_FILLMODE, rNewState.FillMode);
	m_pDirect3DDevice->SetRenderState(D3DRS_CULLMODE, rNewState.CullMode);
	
	// Add the global depth bias
	m_pDirect3DDevice->SetRenderState(D3DRS_DEPTHBIAS, DWORD(rNewState.DepthBias + g_fDepthBiasOffset));
	m_pDirect3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, DWORD(rNewState.SlopeScaleDepthBias));
}
void FD3D9DynamicRHI::SetViewport(UINT MinX,UINT MinY,FLOAT MinZ,UINT MaxX,UINT MaxY,FLOAT MaxZ)
{
	D3DVIEWPORT9 Viewport = { MinX, MinY, MaxX - MinX, MaxY - MinY, MinZ, MaxZ };
	//avoid setting a 0 extent viewport, which the debug runtime doesn't like
	if (Viewport.Width > 0 && Viewport.Height > 0)
	{
		m_pDirect3DDevice->SetViewport(&Viewport);
	}
}

void FD3D9DynamicRHI::SetScissorRect(bool bEnable,UINT uMinX,UINT uMinY,UINT uMaxX,UINT uMaxY)
{
	if(bEnable)
	{
		RECT ScissorRect;
		ScissorRect.left = uMinX;
		ScissorRect.right = uMaxX;
		ScissorRect.top = uMinY;
		ScissorRect.bottom = uMaxY;
		m_pDirect3DDevice->SetScissorRect(&ScissorRect);
	}
	m_pDirect3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE,bEnable);
}

/**
* Set depth bounds test state.  
* When enabled, incoming fragments are killed if the value already in the depth buffer is outside [ClipSpaceNearPos, ClipSpaceFarPos]
*
* @param bEnable - whether to enable or disable the depth bounds test
* @param ClipSpaceNearPos - near point in clip space
* @param ClipSpaceFarPos - far point in clip space
*/
void FD3D9DynamicRHI::SetDepthBoundsTest(bool bEnable, const Common::Vector4& vClipSpaceNearPos, const Common::Vector4& vClipSpaceFarPos, bool bHardwareDepthBounds)
{
	if (bEnable)
	{
		if (bHardwareDepthBounds)
		{
			// convert to normalized device coordinates, which are the units used by Nvidia's D3D depth bounds test driver hack.
			// clamp to valid ranges
			FLOAT MinZ = Math::Clamp<float>( max(vClipSpaceNearPos.z, 0.0f) / vClipSpaceNearPos.w, 0.0f, 1.0f);
			FLOAT MaxZ = Math::Clamp<float>( max(vClipSpaceFarPos.z, 0.0f) / vClipSpaceFarPos.w, 0.0f, 1.0f);

			// enable the depth bounds test
			m_pDirect3DDevice->SetRenderState(D3DRS_ADAPTIVETESS_X,MAKEFOURCC('N','V','D','B'));

			// only set depth bounds if ranges are valid
			if (MinZ <= MaxZ)
			{
				// set the overridden render states which define near and far depth bounds in normalized device coordinates
				// Note: Depth bounds test operates on the value already in the depth buffer, not the incoming fragment!
				m_pDirect3DDevice->SetRenderState(D3DRS_ADAPTIVETESS_Z, DWORD(MinZ));
				m_pDirect3DDevice->SetRenderState(D3DRS_ADAPTIVETESS_W, DWORD(MaxZ));
			}
		}
		else
		{
			// construct a near plane in clip space that will reject any pixels whose z is closer than it
			Plane plnNearPlane = Plane(0.0f, 0.0f, 1.0f, -max(vClipSpaceNearPos.z, 0.0f) / vClipSpaceNearPos.w);
			// construct a far plane in clip space that will reject any pixels whose z is further than it
			Plane plnFarPlane = Plane(0.0f, 0.0f, -1.0f, max(vClipSpaceFarPos.z, 0.0f) / vClipSpaceFarPos.w);

			// turn on the first two planes which are specified through bit 0 and 1
			// @todo: if user clip planes are used for anything else in D3D, use an allocation scheme instead of just always using planes 0 and 1
			// Note: Using clip planes is different from depth bounds test since it operates on the position of the incoming pixel, 
			// so the incoming pixel and the corresponding depth buffer's depths must be the same for dependable results.
			m_pDirect3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0x3);
			m_pDirect3DDevice->SetClipPlane(0, (FLOAT*)&plnNearPlane);
			m_pDirect3DDevice->SetClipPlane(1, (FLOAT*)&plnFarPlane);

			// on cards that implement clip planes by splitting triangles there will be significant z-fighting, so a depth bias is necessary
			g_fDepthBiasOffset = -0.00001;
		}
	}
	else
	{
		if (bHardwareDepthBounds)
		{
			// disable depth bounds test
			m_pDirect3DDevice->SetRenderState(D3DRS_ADAPTIVETESS_X, 0);
		}
		else
		{
			// turn all of the clip planes off
			m_pDirect3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0x0);

			// restore the depth bias to 0
			g_fDepthBiasOffset = 0.0f;
		}
	}
}

/**
* Set bound shader state. This will set the vertex decl/shader, and pixel shader
* @param BoundShaderState - state resource
*/
void FD3D9DynamicRHI::SetBoundShaderState(const BoundShaderState& rBoundShaderState)
{
	// Clear the vertex streams that were used by the old bound shader state.
	ResetVertexStreams();

	check(BoundShaderState->VertexDeclaration);
	m_pDirect3DDevice->SetVertexDeclaration(BoundShaderState->VertexDeclaration);
	m_pDirect3DDevice->SetVertexShader(BoundShaderState->VertexShader);
	if ( BoundShaderState->PixelShader )
	{
		m_pDirect3DDevice->SetPixelShader(BoundShaderState->PixelShader);
	}
	else
	{
		// use special null pixel shader when PixelSahder was set to NULL
		FPixelShaderRHIParamRef NullPixelShaderRHI = TShaderMapRef<FNULLPixelShader>(GetGlobalShaderMap())->GetPixelShader();
		DYNAMIC_CAST_D3D9RESOURCE(PixelShader,NullPixelShader);
		m_pDirect3DDevice->SetPixelShader(NullPixelShader);
	}

	// Prevent transient bound shader states from being recreated for each use by keeping a history of the most recently used bound shader states.
	// The history keeps them alive, and the bound shader state cache allows them to be reused if needed.
	BoundShaderStateHistory.Add(BoundShaderState);
}

void FD3D9DynamicRHI::SetSamplerState(FPixelShaderRHIParamRef PixelShaderRHI,UINT TextureIndex,UINT SamplerIndex,FSamplerStateRHIParamRef NewStateRHI,FTextureRHIParamRef NewTextureRHI,FLOAT MipBias)
{
	DYNAMIC_CAST_D3D9RESOURCE(PixelShader,PixelShader);
	DYNAMIC_CAST_D3D9RESOURCE(SamplerState,NewState);
	DYNAMIC_CAST_D3D9RESOURCE(Texture,NewTexture);

	// Force linear mip-filter if MipBias has a fractional part.
	DWORD MipFilter;
	if (NewState->MipMapLODBias || appIsNearlyEqual(appTruncFloat(MipBias), MipBias))
	{
		MipFilter = NewState->MipFilter;
	}
	else
	{
		MipFilter = D3DTEXF_LINEAR;
	}

	m_pDirect3DDevice->SetTexture(TextureIndex,*NewTexture);
	m_pDirect3DDevice->SetSamplerState(TextureIndex,D3DSAMP_SRGBTEXTURE,NewTexture->IsSRGB());
	m_pDirect3DDevice->SetSamplerState(TextureIndex,D3DSAMP_MAGFILTER,NewState->MagFilter);
	m_pDirect3DDevice->SetSamplerState(TextureIndex,D3DSAMP_MINFILTER,NewState->MinFilter);
	m_pDirect3DDevice->SetSamplerState(TextureIndex,D3DSAMP_MIPFILTER,NewState->MipFilter);
	m_pDirect3DDevice->SetSamplerState(TextureIndex,D3DSAMP_ADDRESSU,NewState->AddressU);
	m_pDirect3DDevice->SetSamplerState(TextureIndex,D3DSAMP_ADDRESSV,NewState->AddressV);
	m_pDirect3DDevice->SetSamplerState(TextureIndex,D3DSAMP_ADDRESSW,NewState->AddressW);
	m_pDirect3DDevice->SetSamplerState(TextureIndex,D3DSAMP_MIPMAPLODBIAS,NewState->MipMapLODBias ? NewState->MipMapLODBias : FLOAT_TO_DWORD(MipBias) );
}

void FD3D9DynamicRHI::SetVertexShaderParameter(FVertexShaderRHIParamRef VertexShaderRHI,UINT BufferIndex,UINT BaseIndex,UINT NumBytes,const void* NewValue)
{
	m_pDirect3DDevice->SetVertexShaderConstantF(
		BaseIndex / NumBytesPerShaderRegister,
		(FLOAT*)GetPaddedShaderParameterValue(NewValue,NumBytes),
		(NumBytes + NumBytesPerShaderRegister - 1) / NumBytesPerShaderRegister
		);
}

/*
* *** PERFORMANCE WARNING *****
* This code is from Mikey W @ Xbox 
* This function is to support single float array parameter in shader
* This pads 3 more floats for each element - at the expensive of CPU/stack memory
* Do not overuse this. If you can, use float4 in shader. 
*/
void FD3D9DynamicRHI::SetVertexShaderFloatArray(FVertexShaderRHIParamRef VertexShaderRHI,UINT BufferIndex,UINT BaseIndex,UINT NumValues,const FLOAT* FloatValues)
{
	// On D3D, this function takes an array of floats and pads them out to an array of vector4's before setting them as
	// vertex shader constants. This is the proper thing to do for Xenon, although please note the pros and cons
	// when using float arrays. The first con is that there's alot of wasted vertex shader constants that could
	// otherwise be saved if the float array was compressed. However, that would require a fair number of shader
	// instructions to decompress, so the overwhleming pro is that the accessing a float array in the shader is
	// trivial. Another con to be aware of is that the use of more shader constants contributes to "constant
	// waterfalling"...a potential performance problem that can not be predicted, but rather must be measured.

	// Temp storage space for the vector4 padded data. (Note: We might want to make this dynamic, but using
	// the stack is cheap and convenient.)
	const UINT GroupSize = 64;
	XMFLOAT4A pPaddedVectorValues[GroupSize];

	// Process a large set of shader constants in groups of a fixed size
	while( NumValues )
	{
		// Number of values to process this time through the loop
		UINT NumValuesThisGroup = Min( NumValues, GroupSize );
		UINT NumValuesThisGroupDiv4 = (NumValuesThisGroup+4-1)/4;

		// For performance, we use the XnaMath intrinsics. Furthermore, we prefer to use XMLoadFloat4A,
		// if we can guarantee pFloatValues is 16-byte aligned
#if  _WIN64
		BOOL bAligned = (((QWORD)FloatValues)%16)==0 ? TRUE : FALSE;
#else
		BOOL bAligned = (((UINT)FloatValues)%16)==0 ? TRUE : FALSE;
#endif
		if( bAligned )
		{
			XMFLOAT4A* pSrc  = (XMFLOAT4A*)FloatValues;  // pFloatValues is 16-byte aligned
			XMFLOAT4A* pDest = pPaddedVectorValues;

			// Load FLOAT values 4 at a time and store them out as padded FLOAT4 values
			for( UINT i=0; i<NumValuesThisGroupDiv4; i++ )
			{
				XMVECTOR V = XMLoadFloat4A( pSrc++ ); // pFloatValues is 16-byte aligned
				XMVectorGetXPtr( (FLOAT*)pDest++, V ); // Write V.x to first component of pDest
				XMVectorGetYPtr( (FLOAT*)pDest++, V ); // Write V.y to first component of pDest
				XMVectorGetZPtr( (FLOAT*)pDest++, V ); // Write V.w to first component of pDest
				XMVectorGetWPtr( (FLOAT*)pDest++, V ); // Write V.z to first component of pDest
			}
		}
		else
		{
			XMFLOAT4* pSrc  = (XMFLOAT4A*)FloatValues;  // pFloatValues is not aligned
			XMFLOAT4* pDest = pPaddedVectorValues;

			// Load FLOAT values 4 at a time and store them out as padded FLOAT4 values
			for( UINT i=0; i<NumValuesThisGroupDiv4; i++ )
			{
				XMVECTOR V = XMLoadFloat4( pSrc++ ); // pFloatValues is not aligned
				XMVectorGetXPtr( (FLOAT*)pDest++, V ); // Write V.x to first component of pDest
				XMVectorGetYPtr( (FLOAT*)pDest++, V ); // Write V.y to first component of pDest
				XMVectorGetZPtr( (FLOAT*)pDest++, V ); // Write V.w to first component of pDest
				XMVectorGetWPtr( (FLOAT*)pDest++, V ); // Write V.z to first component of pDest
			}
		}

		// Set the newly padded vertex shader constants to the D3DDevice
		m_pDirect3DDevice->SetVertexShaderConstantF( BaseIndex / NumBytesPerShaderRegister, (FLOAT*)pPaddedVectorValues, (NumValuesThisGroup*sizeof(FLOAT)*4 + NumBytesPerShaderRegister - 1) / NumBytesPerShaderRegister  );

		// In case we need to continue processing more values, advance to the next group of values
		NumValues	-= NumValuesThisGroup;
		FloatValues	+= NumValuesThisGroup;
		BaseIndex	+= NumValuesThisGroup*NumBytesPerShaderRegister;
	}
}

void FD3D9DynamicRHI::SetVertexShaderBoolParameter(FVertexShaderRHIParamRef VertexShader,UINT BufferIndex,UINT BaseIndex,bool NewValue)
{
	UINT RegisterIndex = BaseIndex / NumBytesPerShaderRegister;
	BOOL Value = NewValue;
	m_pDirect3DDevice->SetVertexShaderConstantB( RegisterIndex, &Value, 1 );
}

void FD3D9DynamicRHI::SetPixelShaderParameter(FPixelShaderRHIParamRef PixelShader,UINT BufferIndex,UINT BaseIndex,UINT NumBytes,const void* NewValue)
{
	m_pDirect3DDevice->SetPixelShaderConstantF(
		BaseIndex / NumBytesPerShaderRegister,
		(FLOAT*)GetPaddedShaderParameterValue(NewValue,NumBytes),
		(NumBytes + NumBytesPerShaderRegister - 1) / NumBytesPerShaderRegister
		);
}

void FD3D9DynamicRHI::SetPixelShaderBoolParameter(FPixelShaderRHIParamRef PixelShader,UINT BufferIndex,UINT BaseIndex,bool NewValue)
{
	UINT RegisterIndex = BaseIndex / NumBytesPerShaderRegister;
	BOOL Value = NewValue;
	m_pDirect3DDevice->SetPixelShaderConstantB( RegisterIndex, &Value, 1 );
}

/**
* Set engine shader parameters for the view.
* @param View					The current view
* @param ViewProjectionMatrix	Matrix that transforms from world space to projection space for the view
* @param ViewOrigin			World space position of the view's origin
*/
void FD3D9DynamicRHI::SetViewParameters( const SceneManager* pSceneMgr, const Matrix4& matViewProjectionMatrix, const Vector4& vViewOrigin )
{
	const Common::Vector4 TranslatedViewOrigin = ViewOrigin + Common::Vector4(View->PreViewTranslation,0);

	m_pDirect3DDevice->SetVertexShaderConstantF( VSR_ViewProjMatrix, (const FLOAT*) &ViewProjectionMatrix, 4 );
	m_pDirect3DDevice->SetVertexShaderConstantF( VSR_ViewOrigin, (const FLOAT*) &TranslatedViewOrigin, 1 );
	m_pDirect3DDevice->SetPixelShaderConstantF( PSR_MinZ_MaxZ_Ratio, (const FLOAT*) &View->InvDeviceZToWorldZTransform, 1 );
	m_pDirect3DDevice->SetPixelShaderConstantF( PSR_ScreenPositionScaleBias, (const FLOAT*) &View->ScreenPositionScaleBias, 1 );
}

// Output state.
void FD3D9DynamicRHI::SetDepthState(FDepthStateRHIParamRef NewStateRHI)
{
	DYNAMIC_CAST_D3D9RESOURCE(DepthState,NewState);

	m_pDirect3DDevice->SetRenderState(D3DRS_ZENABLE,NewState->bZEnable);
	m_pDirect3DDevice->SetRenderState(D3DRS_ZWRITEENABLE,NewState->bZWriteEnable);
	m_pDirect3DDevice->SetRenderState(D3DRS_ZFUNC,NewState->ZFunc);
}
void FD3D9DynamicRHI::SetStencilState(FStencilStateRHIParamRef NewStateRHI)
{
	DYNAMIC_CAST_D3D9RESOURCE(StencilState,NewState);

	m_pDirect3DDevice->SetRenderState(D3DRS_STENCILENABLE,NewState->bStencilEnable);
	m_pDirect3DDevice->SetRenderState(D3DRS_STENCILFUNC,NewState->StencilFunc);
	m_pDirect3DDevice->SetRenderState(D3DRS_STENCILFAIL,NewState->StencilFail);
	m_pDirect3DDevice->SetRenderState(D3DRS_STENCILZFAIL,NewState->StencilZFail);
	m_pDirect3DDevice->SetRenderState(D3DRS_STENCILPASS,NewState->StencilPass);
	m_pDirect3DDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE,NewState->bTwoSidedStencilMode);
	m_pDirect3DDevice->SetRenderState(D3DRS_CCW_STENCILFUNC,NewState->CCWStencilFunc);
	m_pDirect3DDevice->SetRenderState(D3DRS_CCW_STENCILFAIL,NewState->CCWStencilFail);
	m_pDirect3DDevice->SetRenderState(D3DRS_CCW_STENCILZFAIL,NewState->CCWStencilZFail);
	m_pDirect3DDevice->SetRenderState(D3DRS_CCW_STENCILPASS,NewState->CCWStencilPass);
	m_pDirect3DDevice->SetRenderState(D3DRS_STENCILMASK,NewState->StencilReadMask);
	m_pDirect3DDevice->SetRenderState(D3DRS_STENCILWRITEMASK,NewState->StencilWriteMask);
	m_pDirect3DDevice->SetRenderState(D3DRS_STENCILREF,NewState->StencilRef);
}

void FD3D9DynamicRHI::SetBlendState(const BlendState& rNewState)
{
	m_pDirect3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,NewState->bAlphaBlendEnable);
	m_pDirect3DDevice->SetRenderState(D3DRS_BLENDOP,NewState->ColorBlendOperation);
	m_pDirect3DDevice->SetRenderState(D3DRS_SRCBLEND,NewState->ColorSourceBlendFactor);
	m_pDirect3DDevice->SetRenderState(D3DRS_DESTBLEND,NewState->ColorDestBlendFactor);
	m_pDirect3DDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE,NewState->bSeparateAlphaBlendEnable);
	m_pDirect3DDevice->SetRenderState(D3DRS_BLENDOPALPHA,NewState->AlphaBlendOperation);
	m_pDirect3DDevice->SetRenderState(D3DRS_SRCBLENDALPHA,NewState->AlphaSourceBlendFactor);
	m_pDirect3DDevice->SetRenderState(D3DRS_DESTBLENDALPHA,NewState->AlphaDestBlendFactor);

	m_pDirect3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE,NewState->bAlphaTestEnable);
	m_pDirect3DDevice->SetRenderState(D3DRS_ALPHAFUNC,NewState->AlphaFunc);
	m_pDirect3DDevice->SetRenderState(D3DRS_ALPHAREF,NewState->AlphaRef);
}

void FD3D9DynamicRHI::SetRenderTarget( RenderTarget* pNewRenderTarget, Surface* pNewDepthStencilTarget )
{
	// Reset all texture references, to ensure a reference to this render target doesn't remain set.
	for(UINT TextureIndex = 0;TextureIndex < 16;TextureIndex++)
	{
		m_pDirect3DDevice->SetTexture(TextureIndex,NULL);
	}

	if(!pNewRenderTarget)
	{
		// 1. If we're setting a NULL color buffer, we must also set a NULL depth buffer.
		// 2. If we're setting a NULL color buffer, we're going to use the back buffer instead (D3D shortcoming).
		assert( m_pBackBuffer != NULL );
		m_pDirect3DDevice->SetRenderTarget(0, m_pBackBuffer);
	}
	else
	{
		m_pDirect3DDevice->SetRenderTarget(0, pNewRenderTarget);
	}

	m_pDirect3DDevice->SetDepthStencilSurface((pNewDepthStencilTarget ? (IDirect3DSurface9*)*pNewDepthStencilTarget : NULL));

	/*
	// Detect when the back buffer is being set, and set the correct viewport.
	if( DrawingViewport && (!pNewRenderTarget || pNewRenderTarget == m_pBackBuffer) )
	{
		D3DVIEWPORT9 D3DViewport = { 0, 0, DrawingViewport->GetSizeX(), DrawingViewport->GetSizeY(), 0.0f, 1.0f };
		m_pDirect3DDevice->SetViewport(&D3DViewport);
	}
	*/
}
void FD3D9DynamicRHI::SetMRTRenderTarget(RenderTarget* pNewRenderTarget, UINT uTargetIndex)
{
	// Reset all texture references, to ensure a reference to this render target doesn't remain set.
	for(UINT uTextureIndex = 0;uTextureIndex < 16;uTextureIndex++)
		m_pDirect3DDevice->SetTexture(uTextureIndex, NULL);

	m_pDirect3DDevice->SetRenderTarget(uTargetIndex, *pNewRenderTarget);
}

void FD3D9DynamicRHI::SetColorWriteEnable(bool bEnable)
{
	DWORD EnabledStateValue = D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED;
	m_pDirect3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE,bEnable ? EnabledStateValue : 0);
}
void FD3D9DynamicRHI::SetColorWriteMask(UINT ColorWriteMask)
{
	DWORD EnabledStateValue;
	EnabledStateValue  = (ColorWriteMask & CW_RED) ? D3DCOLORWRITEENABLE_RED : 0;
	EnabledStateValue |= (ColorWriteMask & CW_GREEN) ? D3DCOLORWRITEENABLE_GREEN : 0;
	EnabledStateValue |= (ColorWriteMask & CW_BLUE) ? D3DCOLORWRITEENABLE_BLUE : 0;
	EnabledStateValue |= (ColorWriteMask & CW_ALPHA) ? D3DCOLORWRITEENABLE_ALPHA : 0;
	m_pDirect3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE, EnabledStateValue );
}

// Primitive drawing.
D3DPRIMITIVETYPE FD3D9DynamicRHI::_GetD3D9PrimitiveType(UINT uPrimitiveType)
{
	switch(uPrimitiveType)
	{
	case PT_TriangleList: return D3DPT_TRIANGLELIST;
	case PT_TriangleStrip: return D3DPT_TRIANGLESTRIP;
	case PT_LineList: return D3DPT_LINELIST;
	default: assert( !TEXT("Unknown primitive type" ) );
	};

	return D3DPT_TRIANGLELIST;
}

void FD3D9DynamicRHI::DrawPrimitive(UINT uPrimitiveType, UINT uBaseVertexIndex, UINT uNumPrimitives)
{
	if ( !_IsDeviceLost() )
	{
		m_pDirect3DDevice->DrawPrimitive(
			_GetD3D9PrimitiveType(uPrimitiveType),
			uBaseVertexIndex,
			uNumPrimitives
			);

		assert( m_uUpdateStreamForInstancingMask == 0 );
		assert( m_uPendingNumInstances < 2 );
	}
}

void FD3D9DynamicRHI::DrawIndexedPrimitive(IndexBuffer* pIndexBuffer, UINT uPrimitiveType, 
	INT iBaseVertexIndex, UINT uMinIndex, UINT uNumVertices, UINT uStartIndex, UINT uNumPrimitives)
{
	if ( !_IsDeviceLost() )
	{
		m_pDirect3DDevice->SetIndices(pIndexBuffer);
		m_pDirect3DDevice->DrawIndexedPrimitive(
			_GetD3D9PrimitiveType(uPrimitiveType),
			iBaseVertexIndex,
			uMinIndex,
			uNumVertices,
			uStartIndex,
			uNumPrimitives
			);

		if ( m_uPendingNumInstances > 1 && m_uUpdateStreamForInstancingMask )
		{
			for (UINT Instance = 1; Instance < m_uPendingNumInstances; Instance++)
			{
				// Set the instance-indexed vertex streams with a base address of the current instance.
				UINT InstancingMask = m_uUpdateStreamForInstancingMask;
				for (UINT StreamIndex = 0; StreamIndex < NumVertexStreams && InstancingMask; StreamIndex++)
				{
					if (InstancingMask & 1)
					{
						VertexBuffer* pVertexBuffer = m_PendingStreams[StreamIndex].pVertexBuffer;
						m_pDirect3DDevice->SetStreamSource(
							StreamIndex,
							pVertexBuffer,
							m_PendingStreams[StreamIndex].uStride * Instance,
							0
							);
					}
					InstancingMask >>= 1;
				}

				// Draw this instance.
				m_pDirect3DDevice->DrawIndexedPrimitive(
					_GetD3D9PrimitiveType(uPrimitiveType),
					iBaseVertexIndex,
					uMinIndex,
					uNumVertices,
					uStartIndex,
					uNumPrimitives
					);
			}

			// Reset the instanced vertex state.
			UINT InstancingMask = m_uUpdateStreamForInstancingMask;
			for (UINT StreamIndex = 0; StreamIndex < NumVertexStreams && InstancingMask; StreamIndex++)
			{
				if (InstancingMask & 1)
				{
					m_PendingStreams[StreamIndex].pVertexBuffer = 0;
				}
				InstancingMask >>= 1;
			}
			m_uUpdateStreamForInstancingMask = 0;
			m_uPendingNumInstances = 1;
		}
	}
}
/**
* Preallocate memory or get a direct command stream pointer to fill up for immediate rendering . This avoids memcpys below in DrawPrimitiveUP
* @param PrimitiveType The type (triangles, lineloop, etc) of primitive to draw
* @param NumPrimitives The number of primitives in the VertexData buffer
* @param NumVertices The number of vertices to be written
* @param VertexDataStride Size of each vertex 
* @param OutVertexData Reference to the allocated vertex memory
*/
void FD3D9DynamicRHI::BeginDrawPrimitiveUP(UINT uPrimitiveType, UINT uNumPrimitives, UINT uNumVertices, UINT uVertexDataStride, void*& pOutVertexData)
{
	assert( !m_bPendingBegunDrawPrimitiveUP );

	if((UINT)PendingDrawPrimitiveUPVertexData.Num() < uNumVertices * uVertexDataStride)
	{
		PendingDrawPrimitiveUPVertexData.Empty(NumVertices * VertexDataStride);
		PendingDrawPrimitiveUPVertexData.Add(NumVertices * VertexDataStride - PendingDrawPrimitiveUPVertexData.Num());
	}
	OutVertexData = &PendingDrawPrimitiveUPVertexData(0);

	PendingPrimitiveType = PrimitiveType;
	PendingNumPrimitives = NumPrimitives;
	PendingNumVertices = NumVertices;
	PendingVertexDataStride = VertexDataStride;
	PendingBegunDrawPrimitiveUP = TRUE;
}

/**
* Draw a primitive using the vertex data populated since RHIBeginDrawPrimitiveUP and clean up any memory as needed
*/
void FD3D9DynamicRHI::EndDrawPrimitiveUP()
{
	assert( m_bPendingBegunDrawPrimitiveUP );
	m_bPendingBegunDrawPrimitiveUP = FALSE;

	DrawPrimitiveUP(m_uPendingPrimitiveType, m_uPendingNumPrimitives, &m_PendingDrawPrimitiveUPVertexData(0), m_uPendingVertexDataStride);
}
/**
* Draw a primitive using the vertices passed in
* VertexData is NOT created by BeginDrawPrimitveUP
* @param PrimitiveType The type (triangles, lineloop, etc) of primitive to draw
* @param NumPrimitives The number of primitives in the VertexData buffer
* @param VertexData A reference to memory preallocate in RHIBeginDrawPrimitiveUP
* @param VertexDataStride The size of one vertex
*/
void FD3D9DynamicRHI::DrawPrimitiveUP(UINT uPrimitiveType, UINT uNumPrimitives, const void* pVertexData, UINT uVertexDataStride)
{
	if ( !_IsDeviceLost() )
	{
		// Reset vertex stream 0's frequency.
		m_pDirect3DDevice->SetStreamSourceFreq(0,1);

		m_pDirect3DDevice->DrawPrimitiveUP(
			_GetD3D9PrimitiveType(uPrimitiveType),
			uNumPrimitives,
			pVertexData,
			uVertexDataStride
			);
	}
}

/**
* Preallocate memory or get a direct command stream pointer to fill up for immediate rendering . This avoids memcpys below in DrawIndexedPrimitiveUP
* @param PrimitiveType The type (triangles, lineloop, etc) of primitive to draw
* @param NumPrimitives The number of primitives in the VertexData buffer
* @param NumVertices The number of vertices to be written
* @param VertexDataStride Size of each vertex
* @param OutVertexData Reference to the allocated vertex memory
* @param MinVertexIndex The lowest vertex index used by the index buffer
* @param NumIndices Number of indices to be written
* @param IndexDataStride Size of each index (either 2 or 4 bytes)
* @param OutIndexData Reference to the allocated index memory
*/
void FD3D9DynamicRHI::BeginDrawIndexedPrimitiveUP(UINT uPrimitiveType, UINT uNumPrimitives, UINT uNumVertices, UINT uVertexDataStride, void*& pOutVertexData, UINT uMinVertexIndex, UINT uNumIndices, UINT uIndexDataStride, void*& pOutIndexData)
{
	assert( !m_bPendingBegunDrawPrimitiveUP );

	if((UINT)m_PendingDrawPrimitiveUPVertexData.size() < uNumVertices * uVertexDataStride)
	{
		m_PendingDrawPrimitiveUPVertexData.Empty(uNumVertices * uVertexDataStride);
		m_PendingDrawPrimitiveUPVertexData.Add(uNumVertices * uVertexDataStride - PendingDrawPrimitiveUPVertexData.Num());
	}
	pOutVertexData = &m_PendingDrawPrimitiveUPVertexData(0);

	if((UINT)PendingDrawPrimitiveUPIndexData.Num() < NumIndices * IndexDataStride)
	{
		PendingDrawPrimitiveUPIndexData.Empty(NumIndices * IndexDataStride);
		PendingDrawPrimitiveUPIndexData.Add(NumIndices * IndexDataStride - PendingDrawPrimitiveUPIndexData.Num());
	}
	pOutIndexData = &m_PendingDrawPrimitiveUPVertexData(0);

	assert((sizeof(WORD) == IndexDataStride) || (sizeof(DWORD) == IndexDataStride));

	m_uPendingPrimitiveType = uPrimitiveType;
	m_uPendingNumPrimitives = uNumPrimitives;
	m_uPendingMinVertexIndex = uMinVertexIndex;
	m_uPendingIndexDataStride = uIndexDataStride;

	m_uPendingNumVertices = uNumVertices;
	m_uPendingVertexDataStride = uVertexDataStride;

	m_bPendingBegunDrawPrimitiveUP = true;
}

/**
* Draw a primitive using the vertex and index data populated since RHIBeginDrawIndexedPrimitiveUP and clean up any memory as needed
*/
void FD3D9DynamicRHI::EndDrawIndexedPrimitiveUP()
{
	assert( !m_bPendingBegunDrawPrimitiveUP );
	m_bPendingBegunDrawPrimitiveUP = false;

	// for now (while RHIDrawPrimitiveUP still exists), just call it because it does the same work we need here
	DrawIndexedPrimitiveUP(m_uPendingPrimitiveType, m_uPendingMinVertexIndex, m_uPendingNumVertices, m_uPendingNumPrimitives, m_PendingDrawPrimitiveUPIndexData, 
		m_uPendingIndexDataStride, m_PendingDrawPrimitiveUPVertexData, m_uPendingVertexDataStride);
}

/**
* Draw a primitive using the vertices passed in as described the passed in indices. 
* IndexData and VertexData are NOT created by BeginDrawIndexedPrimitveUP
* @param PrimitiveType The type (triangles, lineloop, etc) of primitive to draw
* @param MinVertexIndex The lowest vertex index used by the index buffer
* @param NumVertices The number of vertices in the vertex buffer
* @param NumPrimitives THe number of primitives described by the index buffer
* @param IndexData The memory preallocated in RHIBeginDrawIndexedPrimitiveUP
* @param IndexDataStride The size of one index
* @param VertexData The memory preallocate in RHIBeginDrawIndexedPrimitiveUP
* @param VertexDataStride The size of one vertex
*/
void FD3D9DynamicRHI::DrawIndexedPrimitiveUP(UINT uPrimitiveType, UINT uMinVertexIndex, UINT uNumVertices, UINT uNumPrimitives, const void* pIndexData, UINT uIndexDataStride, const void* pVertexData, UINT uVertexDataStride)
{
	if ( !_IsDeviceLost() )
	{
		// Reset vertex stream 0's frequency.
		m_pDirect3DDevice->SetStreamSourceFreq(0,1);

		m_pDirect3DDevice->DrawIndexedPrimitiveUP(
			GetD3D9PrimitiveType(uPrimitiveType),
			uMinVertexIndex,
			uNumVertices,
			uNumPrimitives,
			pIndexData,
			uIndexDataStride == sizeof(WORD) ? D3DFMT_INDEX16 : D3DFMT_INDEX32,
			pVertexData,
			uVertexDataStride
			);
	}
}

#if 0

/**
* Draw a sprite particle emitter.
*
* @param Mesh The mesh element containing the data for rendering the sprite particles
*/
void FD3D9DynamicRHI::DrawSpriteParticles(const FMeshElement& Mesh)
{
	check(Mesh.DynamicVertexData);
	FDynamicSpriteEmitterData* SpriteData = (FDynamicSpriteEmitterData*)(Mesh.DynamicVertexData);

	// Sort the particles if required
	INT ParticleCount = SpriteData->Source.ActiveParticleCount;

	// 'clamp' the number of particles actually drawn
	//@todo.SAS. If sorted, we really want to render the front 'N' particles...
	// right now it renders the back ones. (Same for SubUV draws)
	INT StartIndex = 0;
	INT EndIndex = ParticleCount;
	if ((SpriteData->Source.MaxDrawCount >= 0) && (ParticleCount > SpriteData->Source.MaxDrawCount))
	{
		ParticleCount = SpriteData->Source.MaxDrawCount;
	}

	TArray<FParticleOrder>* ParticleOrder = (TArray<FParticleOrder>*)(Mesh.DynamicIndexData);

	// Render the particles are indexed tri-lists
	void* OutVertexData = NULL;
	void* OutIndexData = NULL;

	// Get the memory from the device for copying the particle vertex/index data to
	RHIBeginDrawIndexedPrimitiveUP(PT_TriangleList, 
		ParticleCount * 2, ParticleCount * 4, Mesh.DynamicVertexStride, OutVertexData, 
		0, ParticleCount * 6, sizeof(WORD), OutIndexData);

	if (OutVertexData && OutIndexData)
	{
		// Pack the data
		FParticleSpriteVertex* Vertices = (FParticleSpriteVertex*)OutVertexData;
		SpriteData->GetVertexAndIndexData(Vertices, OutIndexData, ParticleOrder);
		// End the draw, which will submit the data for rendering
		RHIEndDrawIndexedPrimitiveUP();
	}
}



/**
* Draw a sprite subuv particle emitter.
*
* @param Mesh The mesh element containing the data for rendering the sprite subuv particles
*/
void FD3D9DynamicRHI::DrawSubUVParticles(const FMeshElement& Mesh)
{
	check(Mesh.DynamicVertexData);
	FDynamicSubUVEmitterData* SubUVData = (FDynamicSubUVEmitterData*)(Mesh.DynamicVertexData);

	// Sort the particles if required
	INT ParticleCount = SubUVData->Source.ActiveParticleCount;

	// 'clamp' the number of particles actually drawn
	//@todo.SAS. If sorted, we really want to render the front 'N' particles...
	// right now it renders the back ones. (Same for SubUV draws)
	INT StartIndex = 0;
	INT EndIndex = ParticleCount;
	if ((SubUVData->Source.MaxDrawCount >= 0) && (ParticleCount > SubUVData->Source.MaxDrawCount))
	{
		ParticleCount = SubUVData->Source.MaxDrawCount;
	}

	TArray<FParticleOrder>* ParticleOrder = (TArray<FParticleOrder>*)(Mesh.DynamicIndexData);

	// Render the particles are indexed tri-lists
	void* OutVertexData = NULL;
	void* OutIndexData = NULL;

	// Get the memory from the device for copying the particle vertex/index data to
	RHIBeginDrawIndexedPrimitiveUP(PT_TriangleList, 
		ParticleCount * 2, ParticleCount * 4, Mesh.DynamicVertexStride, OutVertexData, 
		0, ParticleCount * 6, sizeof(WORD), OutIndexData);

	if (OutVertexData && OutIndexData)
	{
		// Pack the data
		FParticleSpriteSubUVVertex* Vertices = (FParticleSpriteSubUVVertex*)OutVertexData;
		SubUVData->GetVertexAndIndexData(Vertices, OutIndexData, ParticleOrder);
		// End the draw, which will submit the data for rendering
		RHIEndDrawIndexedPrimitiveUP();
	}
}

#endif

// Raster operations.
void FD3D9DynamicRHI::Clear(bool bClearColor,const Common::ColourValue& rColor, bool bClearDepth, float fDepth, bool bClearStencil, DWORD dwStencil)
{
	// Determine the clear flags.
	DWORD Flags = 0;
	if(bClearColor)
	{
		Flags |= D3DCLEAR_TARGET;
	}
	if(bClearDepth)
	{
		Flags |= D3DCLEAR_ZBUFFER;
	}
	if(bClearStencil)
	{
		Flags |= D3DCLEAR_STENCIL;
	}

	// Clear the render target/depth-stencil surfaces based on the flags.
	m_pDirect3DDevice->Clear(0, NULL, Flags, D3DCOLOR_COLORVALUE(rColor.r, rColor.g, rColor.b, rColor.a), fDepth, dwStencil);
}

/*
* Returns the total GPU time taken to render the last frame. Same metric as appCycles().
*/
DWORD FD3D9DynamicRHI::GetGPUFrameCycles()
{
	return m_GPUFrameTime;
}

/*
* Returns an approximation of the available memory that textures can use, which is video + AGP where applicable, rounded to the nearest MB, in MB.
*/
DWORD FD3D9DynamicRHI::GetAvailableTextureMemory()
{
	//apparently GetAvailableTextureMem() returns available bytes (the docs don't say) rounded to the nearest MB.
	return m_pDirect3DDevice->GetAvailableTextureMem() / 1048576;
}

bool FD3D9DynamicRHI::_IsDeviceLost(void)
{
	return	m_pDirect3DDevice->TestCooperativeLevel() != D3D_OK;
}